package com.closer.codebox.biz.python;

import com.closer.codebox.biz.CommonTemplate;
import com.closer.codebox.biz.MemoryMonitorService;
import com.closer.codebox.support.dto.ExecuteCodeRequest;
import com.closer.codebox.support.dto.JudgeCase;
import com.closer.codebox.support.dto.JudgeConfig;
import com.closer.codebox.support.dto.JudgeInfo;
import com.closer.codebox.support.enums.JudgeInfoMessageEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class PythonCodeSandbox extends CommonTemplate {

    private final MemoryMonitorService memoryMonitorService;

    public PythonCodeSandbox(MemoryMonitorService memoryMonitorService) {
        this.memoryMonitorService = memoryMonitorService;
    }

    public JudgeInfo executeCode(ExecuteCodeRequest params) {
        var code = params.getCode();

        // 1. 保存代码文件
        var userCodeFile = saveCodeToFile(code, "main.py", "python");

        // 2. 运行代码（Python不需要编译）
        var result = runFile(userCodeFile, params.getTestCases(), params.getJudgeConfig());

        cleanTempFiles(userCodeFile);
        return JudgeInfo.builder()
                .message(result.getMessage())
                .memory(result.getMemory())
                .time(result.getTime())
                .build();
    }

    /**
     * 运行Python文件
     * @param file Python文件
     * @param testCases 测试用例
     * @param judgeConfig 判题配置
     * @return 判题结果
     */
    public JudgeInfo runFile(File file, List<JudgeCase> testCases, JudgeConfig judgeConfig) {
        var timeLimit = judgeConfig.getTimeLimit();
        var maxTime = 0L;
        var maxMemory = 0L;

        // 获取Python命令（根据系统选择合适的Python解释器）
        var pythonCommand = getPythonCommand();

        for (var testCase : testCases) {
            var input = testCase.getInput();
            var expectedOutput = testCase.getOutput();
            Process process = null;

            try {
                var startTime = System.currentTimeMillis();
                var command = new ArrayList<String>();
                command.add(pythonCommand);
                command.add(file.getAbsolutePath());

                var processBuilder = new ProcessBuilder(command);
                processBuilder.directory(file.getParentFile());
                processBuilder.redirectErrorStream(true);

                process = processBuilder.start();

                final long finalPid = process.pid();
                var memoryFuture = CompletableFuture.supplyAsync(() ->
                        memoryMonitorService.monitorPeakMemory(finalPid, timeLimit + 1000)
                );

                // 写入输入
                if (input != null && !input.isEmpty()) {
                    try (var outputStream = process.getOutputStream();
                         var writer = new OutputStreamWriter(outputStream)) {
                        writer.write(input);
                        writer.flush();
                    }
                }

                // 读取输出
                var outputBuilder = new StringBuilder();
                try (var inputStream = process.getInputStream();
                     var reader = new BufferedReader(new InputStreamReader(inputStream))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        outputBuilder.append(line);
                        if (reader.ready()) {
                            outputBuilder.append("\n");
                        }
                    }
                }

                // 等待进程完成并获取执行时间
                var finished = process.waitFor(timeLimit, TimeUnit.MILLISECONDS);
                var endTime = System.currentTimeMillis();
                var executionTime = endTime - startTime;

                var peakMemoryUsage = memoryFuture.get(timeLimit + 2000, TimeUnit.MILLISECONDS);

                if (!finished) {
                    process.destroyForcibly();
                    return JudgeInfo.builder()
                            .message(JudgeInfoMessageEnum.TIME_LIMIT_EXCEEDED.getValue())
                            .time(maxTime)
                            .memory(maxMemory)
                            .build();
                }

                // 检查退出代码
                int exitCode = process.exitValue();
                if (exitCode != 0) {
                    // 读取错误信息
                    var errorOutput = new StringBuilder();
                    try (var errorStream = process.getErrorStream();
                         var errorReader = new BufferedReader(new InputStreamReader(errorStream))) {
                        String line;
                        while ((line = errorReader.readLine()) != null) {
                            errorOutput.append(line).append("\n");
                        }
                    }

                    log.error("Python运行时错误，退出码: {}, 错误信息: {}", exitCode, errorOutput.toString());

                    return JudgeInfo.builder()
                            .message(JudgeInfoMessageEnum.RUNTIME_ERROR.getValue())
                            .time(executionTime)
                            .memory(peakMemoryUsage)
                            .build();
                }

                // 更新最大时间和内存
                maxTime = Math.max(maxTime, executionTime);
                maxMemory = Math.max(maxMemory, peakMemoryUsage);

                // 检查内存限制
                if (maxMemory > judgeConfig.getMemoryLimit() * 1024) {
                    return JudgeInfo.builder()
                            .message(JudgeInfoMessageEnum.MEMORY_LIMIT_EXCEEDED.getValue())
                            .time(maxTime)
                            .memory(maxMemory)
                            .build();
                }

                var actualOutput = outputBuilder.toString().trim();
                log.info("Python测试用例 - 输入: [{}], 预期输出: [{}], 实际输出: [{}], 内存: {}KB, 时间: {}ms",
                        input, expectedOutput, actualOutput, peakMemoryUsage, executionTime);

                if (!actualOutput.equals(expectedOutput)) {
                    return JudgeInfo.builder()
                            .message(JudgeInfoMessageEnum.WRONG_ANSWER.getValue())
                            .time(maxTime)
                            .memory(maxMemory)
                            .build();
                }

            } catch (Exception e) {
                if (process != null && process.isAlive()) {
                    process.destroyForcibly();
                }
                log.error("执行Python测试用例时发生错误: {}", e.getMessage());
                return JudgeInfo.builder()
                        .message(JudgeInfoMessageEnum.RUNTIME_ERROR.getValue())
                        .time(maxTime)
                        .memory(maxMemory)
                        .build();
            }
        }

        return JudgeInfo.builder()
                .message(JudgeInfoMessageEnum.ACCEPTED.getValue())
                .time(maxTime)
                .memory(maxMemory)
                .build();
    }

    /**
     * 获取Python命令
     * 优先尝试python3，如果不存在则使用python
     */
    private String getPythonCommand() {
        var isWindows = System.getProperty("os.name").toLowerCase().contains("windows");

        // 在Windows上尝试python命令，在Unix-like系统上优先尝试python3
        if (isWindows) {
            return "python";
        } else {
            // 检查python3是否可用
            try {
                Process process = Runtime.getRuntime().exec("python3 --version");
                if (process.waitFor(2, TimeUnit.SECONDS) && process.exitValue() == 0) {
                    return "python3";
                }
            } catch (Exception e) {
                log.warn("python3不可用，将使用python命令");
            }
            return "python";
        }
    }

    /**
     * 检查Python环境是否可用
     */
    public boolean checkPythonEnvironment() {
        try {
            var pythonCommand = getPythonCommand();
            Process process = Runtime.getRuntime().exec(pythonCommand + " --version");
            return process.waitFor(2, TimeUnit.SECONDS) && process.exitValue() == 0;
        } catch (Exception e) {
            log.error("Python环境检查失败: {}", e.getMessage());
            return false;
        }
    }
}